import pwd
import json
import subprocess
import os
from datetime import datetime
import platform
import uuid
import socket

import configs


def get_system_users():
    """
    获取系统中所有用户的详细信息。

    返回:
        list: 包含每个用户详细信息的字典列表。

    在 get_system_users 函数里，从 pwd.struct_passwd 对象获取的用户详细信息，对应类Unix系统密码数据库中的各个字段，下面为你逐一解释：

    1. name（pwd_entry.pw_name）
    含义：用户的登录名，这是用户登录系统时使用的名称。
    示例：root、john 等。
    2. uid（pwd_entry.pw_uid）
    含义：用户的唯一标识符（User ID），在系统中每个用户都有一个独一无二的 UID，系统通过 UID 来识别和管理用户。
    示例：0 通常代表 root 用户，普通用户的 UID 一般从 1000 开始。
    3. gid（pwd_entry.pw_gid）
    含义：用户的主要组标识符（Group ID），每个用户都属于一个主要组，系统利用 GID 来管理用户对文件和资源的访问权限。
    示例：0 通常代表 root 组。
    4. gecos（pwd_entry.pw_gecos）
    含义：一般包含用户的真实姓名、办公室位置、电话号码等额外信息，也被称为用户注释字段。这些信息并非强制填写，可能为空。
    示例：John Doe, Room 101, ext. 1234。
    5. home（pwd_entry.pw_dir）
    含义：用户的主目录路径，用户登录系统后默认进入的目录，用户的个人文件通常存放在这里。
    示例：/home/john 是普通用户 john 的主目录，/root 是 root 用户的主目录。
    6. shell（pwd_entry.pw_shell）
    含义：用户登录系统后使用的默认命令行解释器程序路径。
    示例：/bin/bash 是最常见的命令行解释器，/bin/zsh 也是常用的一种。
    """
    users = []
    try:
        # 遍历系统中的所有用户条目
        for pwd_entry in pwd.getpwall():
            user_info = {
                "name": pwd_entry.pw_name,
                "uid": pwd_entry.pw_uid,
                "gid": pwd_entry.pw_gid,
                "gecos": pwd_entry.pw_gecos,
                "home": pwd_entry.pw_dir,
                "shell": pwd_entry.pw_shell,
            }
            users.append(user_info)
    except Exception as e:
        print(f"获取用户信息时出错: {e}")
        return None
    return json.dumps(users, indent=4)


# print(get_system_users())


def get_system_services():
    """
    获取 Linux 系统中所有服务的详细信息，并将结果整理成 JSON 格式。

    返回:
        str: 包含服务详细信息的 JSON 字符串，如果出错则返回 None。

    1. unit
    含义：服务单元的名称，在 systemd 管理体系里，服务以单元文件的形式存在，unit 就是这个单元文件的名字。
    示例：systemd-timesyncd.service 代表系统时间同步服务的单元名称，该服务用于让系统时间与网络时间服务器保持同步。
    2. load
    含义：表示服务单元文件是否成功加载到 systemd 中。
    取值说明：
    loaded：服务单元文件已成功加载到 systemd 里。
    not-found：systemd 未能找到对应的服务单元文件。
    error：加载服务单元文件时出现错误。
    3. active
    含义：描述服务的总体激活状态，反映服务是否处于正常工作状态。
    取值说明：
    active：服务当前正在运行或者处于激活状态。
    inactive：服务当前没有运行。
    failed：服务启动失败，处于错误状态。
    4. sub
    含义：提供服务激活状态的更详细信息，依据服务类型的不同，其取值也会有所不同。
    取值说明：
    running：对于守护进程类服务，该值表示服务进程正在运行。
    exited：对于一次性运行的服务，该值表示服务已经正常退出。
    dead：服务已经停止运行。
    5. description
    含义：服务的简要描述信息，用于向用户说明该服务的功能。
    示例：Network Time Synchronization 表明 systemd-timesyncd.service 服务的功能是进行网络时间同步。
    """
    try:
        # 执行 systemctl 命令获取所有服务信息
        result = subprocess.run(
            [
                "systemctl",
                "list-units",
                "--type=service",
                "--all",
                "--no-pager",
                "--no-legend",
                "-o",
                "json",
            ],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
        )
        if result.returncode == 0:
            services = json.loads(result.stdout)
            return json.dumps(services, indent=4)
        else:
            print(f"执行命令出错: {result.stderr}")
            return None
    except Exception as e:
        print(f"获取服务信息时出错: {e}")
        return None


# print(get_system_services())


def get_system_processes():
    """
    获取 Linux 系统中所有进程的详细信息，并将结果整理成 JSON 格式。

    返回:
        str: 包含进程详细信息的 JSON 字符串，如果出错则返回 None。

    pid：进程的唯一标识符（Process ID）。在 Linux 系统里，每个进程都有一个独一无二的 PID，系统借助 PID 来管理和识别进程。例如，1234 就是某个进程在系统中的标识。
    name：进程的名称。一般是进程对应的可执行文件的名称，像 python3 就表明这是一个 Python 3 程序进程。
    username：运行该进程的用户 ID。在 /proc/<pid>/status 文件里，Uid 字段会给出用户的不同 UID 信息，这里提取的是实际运行进程的用户 UID，1000 通常是普通用户的 UID。
    status：进程的状态。常见的状态有：
    R：运行或可运行（在运行队列中）。
    S：可中断的睡眠（等待某个事件完成）。
    D：不可中断的睡眠（通常在等待 I/O 操作）。
    Z：僵尸进程（进程已终止，但父进程尚未回收其资源）。
    T：停止（进程被暂停，例如通过 SIGSTOP 信号）。
    create_time：进程的创建时间。以 YYYY-MM-DD HH:MM:SS 格式呈现，代表进程在系统中创建的具体时间。
    """
    process_list = []
    proc_dir = "/proc"
    try:
        for entry in os.listdir(proc_dir):
            if entry.isdigit():
                pid = entry
                try:
                    # 获取进程名
                    with open(os.path.join(proc_dir, pid, "comm"), "r") as f:
                        name = f.read().strip()
                    # 获取进程状态
                    with open(os.path.join(proc_dir, pid, "status"), "r") as f:
                        status_lines = f.readlines()
                        status_info = {}
                        for line in status_lines:
                            parts = line.split(":", 1)
                            if len(parts) == 2:
                                key = parts[0].strip()
                                value = parts[1].strip()
                                status_info[key] = value
                        username = status_info.get("Uid", "").split("\t")[1]
                        status = (
                            status_info.get("State", "").split("(")[1].split(")")[0]
                        )
                    # 获取进程创建时间
                    stat_path = os.path.join(proc_dir, pid, "stat")
                    with open(stat_path, "r") as f:
                        stat_info = f.read().split()
                        create_time = int(stat_info[21])
                        boot_time = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
                        create_timestamp = os.times().elapsed - (
                            create_time / boot_time
                        )
                        create_time_str = datetime.fromtimestamp(
                            create_timestamp
                        ).strftime("%Y-%m-%d %H:%M:%S")

                    process_info = {
                        "pid": int(pid),
                        "name": name,
                        "username": username,
                        "status": status,
                        "create_time": create_time_str,
                    }
                    process_list.append(process_info)
                except Exception as e:
                    continue
        return json.dumps(process_list, indent=4)
    except Exception as e:
        print(f"获取进程信息时出错: {e}")
        return None


# print(get_system_processes())


def get_system_info():
    """
    使用 platform 模块获取平台的详细信息，并将结果整理成 JSON 格式。

    返回:
        str: 包含平台详细信息的 JSON 字符串。

        system：操作系统的名称，如 Linux、Windows 或 Darwin（macOS）。
        node：计算机的网络名称，通常是主机名。
        release：操作系统的发行版本号，例如 Linux 内核版本号。
        version：操作系统的详细版本信息，包含编译时间、发行版等额外信息。
        machine：硬件架构类型，如 x86_64 表示 64 位的 x86 架构。
        processor：处理器的名称或类型，不过有时可能返回硬件架构类型，因为某些系统无法准确获取处理器名称。
        python_version：当前运行的 Python 解释器的版本号。
        platform：一个综合的字符串，包含操作系统、内核版本、硬件架构等信息。
    """
    platform_info = {
        "system": platform.system(),
        "node": platform.node(),
        "release": platform.release(),
        "version": platform.version(),
        "machine": platform.machine(),
        "processor": platform.processor(),
        "python_version": platform.python_version(),
        "platform": platform.platform(),
        # 'uname': dict(zip(('system', 'node', 'release', 'version', 'machine', 'processor'), platform.uname()))
    }
    return json.dumps(platform_info, indent=4)


# print(get_system_info())



#region 原子函数

def get_ipv4() -> str | None:
    try:
        # 创建一个 UDP 套接字
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # 尝试连接到一个公共 IP 地址和端口
        s.connect((configs.host, configs.port))
        # 获取本机的 IP 地址
        local_ip = s.getsockname()[0]
        s.close()
    except Exception as e:
        err(f"获取本机 IP 地址时出错: {e}")
        local_ip = None
    return local_ip


def get_mac() -> str:
    mac = uuid.getnode()
    mac_hex = ":".join(("%012X" % mac)[i : i + 2] for i in range(0, 12, 2))
    return mac_hex


def get_uptime() -> str:
    try:
        result = subprocess.run(
            ["uptime", "-p"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
        )
        if result.returncode == 0:
            uptime = result.stdout.strip()
        else:
            err(f"执行 uptime 命令出错: {result.stderr}")
    except Exception as e:
        err(f"获取开机时间时出错: {e}")
    return uptime


def get_system_load():
    """
    使用 os.getloadavg() 函数获取系统负载信息。

    返回:
        tuple: 包含过去 1 分钟、5 分钟和 15 分钟的平均负载的元组，如果出错则返回 None。
    """
    try:
        load_1min, load_5min, load_15min = os.getloadavg()
        return load_1min, load_5min, load_15min
    except Exception as e:
        err(f"获取系统负载时出错: {e}")
        return None




def log(message: str):
    print(f"[agent][utils]Log:{message}")


def err(message: str):
    print(f"[agent][utils]Error:{message}")

#endregion 原子函数

def collect_server_status():
    """
    收集服务器的多项状态信息，并将这些信息整理成 JSON 字符串返回。

    - MAC 地址：通过 `get_mac` 函数获取。
    - IPv4 地址：通过 `get_ipv4` 函数获取。
    - 开机时长：通过 `get_uptime` 函数获取。
    - 过去 5 分钟的系统平均负载：通过 `get_system_load` 函数获取。
    - 服务器网络名
    Returns:
        str: 包含服务器状态信息的 JSON 字符串。如果在获取信息过程中出现异常，
             异常信息会在相应的辅助函数中处理，此函数可能会返回包含部分或全部为 None 的信息的 JSON 字符串。
    """
    return json.dumps({"mac_address": get_mac(), "ipv4": get_ipv4(), "uptime": get_uptime(),"5min_load":get_system_load()[1],"node_name": platform.node(),})



# print(collect_server_status())